// AESEncRegKey.cpp : implementation file
//

#include "stdafx.h"
#include "AESEncRegKey.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CAESEncRegKey

CAESEncRegKey::CAESEncRegKey() : _hKey( NULL )
{
    CString szCompanyName = AfxGetAppName();

    CString szSubKey = _T("Software\\") + szCompanyName;

    SetSubKey( szSubKey );
}

CAESEncRegKey::CAESEncRegKey(const BYTE* cbKey, UINT nKeyLength, const BYTE* cbIV, UINT nIVLength) : _hKey( NULL )
{
    ASSERT( NULL != cbKey );
    ASSERT( NULL != cbIV );

    SetHKEY( NULL );

    SetKey( cbKey, nKeyLength );

    SetIV( cbIV, nIVLength );
}

CAESEncRegKey::CAESEncRegKey(HKEY hKey, LPCTSTR pszSubKey, LPCTSTR pszValueName)
{
    SetHKEY( hKey );

    SetSubKey( pszSubKey );

    SetValueName( pszValueName );
}

CAESEncRegKey::~CAESEncRegKey() { }

const BYTE* CAESEncRegKey::GetKey() const
{
  return _EncKey._cbKey;
}

const BYTE* CAESEncRegKey::GetIV() const
{
    return _EncIV._cbIV;
}

UINT CAESEncRegKey::GetIVLength() const
{
    return CryptoPP::AES::BLOCKSIZE;
}

UINT CAESEncRegKey::GetKeyLength() const
{
    return CryptoPP::AES::DEFAULT_KEYLENGTH;
}

const CString& CAESEncRegKey::GetSubKey() const
{
    return _szSubKey;
}

const CString& CAESEncRegKey::GetValueName() const
{
    return _szValueName;
}

BOOL CAESEncRegKey::SetHKEY(HKEY hKey) 
{
    _hKey = hKey;

    return TRUE;
}

BOOL CAESEncRegKey::SetSubKey(LPCTSTR pszSubKey)
{
    BOOL bResult = FALSE;

    ASSERT( NULL != pszSubKey );

    if( NULL != pszSubKey ) {

        CString szTemp = pszSubKey;

        // Strip leading slashes. Windows 9x can deal with them,
        //   but Windows NT/2000 cannot
        while( 0 < szTemp.GetLength() && _T('\\') == szTemp.Left( 1 ) ) {

            szTemp = szTemp.Right( szTemp.GetLength() - 1 );
        }
    
        _szSubKey = szTemp;

        bResult = TRUE;

        ::OutputDebugString( _T("_szSubKey set to ") );
        ::OutputDebugString( _szSubKey );
        ::OutputDebugString( _T("\n") );
    }

    return bResult;
}

BOOL CAESEncRegKey::SetValueName(LPCTSTR pszValueName)
{
    BOOL bResult = FALSE;

    ASSERT( NULL != pszValueName );

    if( NULL != pszValueName ) {
    
        _szValueName = pszValueName;

        bResult = TRUE;

        ::OutputDebugString( _T("_szValueName set to ") );
        ::OutputDebugString( _szValueName );
        ::OutputDebugString( _T("\n") );
    }

    return bResult;
}

BOOL CAESEncRegKey::SetIV(const BYTE *cbIV, UINT nLength)
{
    BOOL bResult = FALSE;

    ASSERT( CryptoPP::AES::BLOCKSIZE == nLength );
    ASSERT( NULL != cbIV );

    if( CryptoPP::AES::BLOCKSIZE == nLength && NULL != cbIV ) {
    
        _EncIV = cbIV;

        bResult = TRUE;
    }

    return bResult;
}

BOOL CAESEncRegKey::SetKey(const BYTE *cbKey, UINT nLength)
{
    BOOL bResult = FALSE;

    ASSERT( CryptoPP::AES::DEFAULT_KEYLENGTH == nLength );
    ASSERT( NULL != cbKey );

    if( CryptoPP::AES::DEFAULT_KEYLENGTH == nLength && NULL != cbKey ) {
    
        _EncKey = cbKey;

        bResult = TRUE;
    }

    return bResult;
}


LONG CAESEncRegKey::WriteString(LPCTSTR pszData, BOOL bEncrypt /*=FALSE*/) const
{
    LONG lResult = ERROR_SUCCESS;

    if( TRUE == bEncrypt ) {

        lResult = WriteEncString( pszData );

    } else {

        lResult = WriteNonEncString( pszData );
    }

    return lResult;
}

LONG CAESEncRegKey::WriteDWORD(DWORD dwValue, BOOL bEncrypt /*=FALSE*/) const
{
    LONG lResult = ERROR_SUCCESS;

    if( TRUE == bEncrypt ) {

        lResult = WriteEncDWORD( dwValue );

    } else {

        lResult = WriteNonEncDWORD( dwValue );
    }

    return lResult;
}

LONG CAESEncRegKey::WriteBinary(const BYTE *pcbData, UINT nSize, BOOL bEncrypt /*= FALSE*/) const
{
    LONG lResult = ERROR_SUCCESS;

    if( TRUE == bEncrypt ) {

        lResult = WriteEncBinary( pcbData, nSize );

    } else {

        lResult = WriteNonEncBinary( pcbData, nSize );
    }

    return lResult;
}

LONG CAESEncRegKey::WriteNonEncString(LPCTSTR pszData) const
{
    LONG lResult = ERROR_SUCCESS;

    lResult = WriteData( reinterpret_cast<const BYTE*>( pszData ),
                       ( ::lstrlen( pszData ) + 1 ) * sizeof( TCHAR ),
                       REG_SZ );

    return lResult;
}

LONG CAESEncRegKey::WriteNonEncDWORD(DWORD dwData) const
{
    LONG lResult = ERROR_SUCCESS;

    lResult = WriteData( reinterpret_cast<const BYTE*>( &dwData ),
                         sizeof( DWORD ), REG_DWORD );

    return lResult;
}


LONG CAESEncRegKey::WriteEncDWORD(DWORD dwData) const
{
    LONG lResult = ERROR_SUCCESS;

    // Returned from EncryptData()
    BYTE* pcbEncryptedData = NULL;
    DWORD dwEncryptedSize = 0;

    //
    // Anti-snoop it...
    lResult = EncryptData( reinterpret_cast<const BYTE*>(&dwData), sizeof( DWORD ), 
                           &pcbEncryptedData, &dwEncryptedSize );

    //
    // Sanity Check
    if( ERROR_SUCCESS != lResult ) { goto FINISHED; }

    //
    // Save it...
    lResult = WriteNonEncBinary( pcbEncryptedData, dwEncryptedSize );

FINISHED:

    //
    // Cleanup...
    if( NULL != pcbEncryptedData ) { delete[] pcbEncryptedData; }

    return lResult;
}

LONG CAESEncRegKey::WriteEncString(LPCTSTR pszData) const
{
    LONG lResult = ERROR_SUCCESS;

    // Returned from EncryptData()
    BYTE* pcbEncryptedData = NULL;
    DWORD dwEncryptedSize = 0;

    //
    // Anti-snoop it...
    lResult = EncryptData( reinterpret_cast<const BYTE*>(pszData),
                           ( ::lstrlen( pszData ) + 1 ) * sizeof( TCHAR ),
                           &pcbEncryptedData, &dwEncryptedSize );

    //
    // Sanity Check
    if( ERROR_SUCCESS != lResult ) { goto FINISHED; }

    //
    // Save it...
    lResult = WriteNonEncBinary( pcbEncryptedData, dwEncryptedSize );

FINISHED:

    //
    // Cleanup...
    if( NULL != pcbEncryptedData ) { delete[] pcbEncryptedData; }

    return lResult;
}

LONG CAESEncRegKey::WriteEncBinary(const BYTE *pcbData, UINT nSize) const
{
    LONG lResult = ERROR_SUCCESS;

    // Returned from EncryptData()
    BYTE* pcbEncryptedData = NULL;
    DWORD dwEncryptedSize = 0;

    //
    // Anti-snoop it...
    lResult = EncryptData( pcbData, nSize, &pcbEncryptedData, &dwEncryptedSize );

    //
    // Sanity Check
    if( ERROR_SUCCESS != lResult ) { goto FINISHED; }

    //
    // Persit it...
    lResult = WriteNonEncBinary( pcbEncryptedData, dwEncryptedSize );

FINISHED:

    //
    // Cleanup...
    if( NULL != pcbEncryptedData ) { delete[] pcbEncryptedData; }

    return lResult;
}

LONG CAESEncRegKey::WriteNonEncBinary(const BYTE *pcbData, UINT nSize) const
{
    LONG lResult = ERROR_SUCCESS;

    lResult = WriteData( pcbData, nSize, REG_BINARY );

    return lResult;
}

LONG CAESEncRegKey::ReadDWORD(DWORD &dwValue, BOOL bEncrypted) const
{
    LONG lResult = ERROR_SUCCESS;

    if( TRUE == bEncrypted ) {

        lResult = ReadEncDWORD( dwValue );

    } else {

        lResult = ReadNonEncDWORD( dwValue );
    }

    return lResult;
}

LONG CAESEncRegKey::ReadString(CString &szValue, BOOL bEncrypted /*=FALSE*/) const
{
    LONG lResult = ERROR_SUCCESS;

    if( TRUE == bEncrypted ) {

        lResult = ReadEncString( szValue );

    } else {

        lResult = ReadNonEncString( szValue );
    }

    return lResult;
}

LONG CAESEncRegKey::ReadString(LPTSTR pszValue, DWORD *dwCharCount, BOOL bEncrypted /*=FALSE*/) const
{
    LONG    lResult = ERROR_SUCCESS;
    CString szTemp;
    DWORD   dwRequiredSize = 0;     // In TCHARs, not BYTEs

    //
    // Emulate the RegQueryValue(...) Function
    //   See http://msdn.microsoft.com/library/default.asp?
    //       url=/library/en-us/sysinfo/base/regqueryvalueex.asp
    //   It appears Caller is asking for dwType
    if( NULL == pszValue && NULL == dwCharCount ) {     
        lResult = ERROR_SUCCESS;
        goto FINISHED;
    }

    if( TRUE == bEncrypted ) {

        lResult = ReadEncString( szTemp );

    } else {

        lResult = ReadNonEncString( szTemp );
    }

    //
    // Sanity Check
    if( ERROR_SUCCESS != lResult ) { goto FINISHED; }

    //
    // '+ 1' to catch the trailing '\0'
    dwRequiredSize = szTemp.GetLength() + 1;

    //
    // Emulate the RegQueryValue(...) Function
    //   See http://msdn.microsoft.com/library/default.asp?
    //       url=/library/en-us/sysinfo/base/regqueryvalueex.asp
    //   It appears Caller is asking for size of pszValue
    if( *dwCharCount < dwRequiredSize && NULL != pszValue ) {

        lResult = ERROR_MORE_DATA;
        *dwCharCount = dwRequiredSize;

        goto FINISHED;
    }

    //
    // Emulate the RegQueryValue(...) Function
    //   See http://msdn.microsoft.com/library/default.asp?
    //       url=/library/en-us/sysinfo/base/regqueryvalueex.asp
    //   Caller is asking for size of pszValue
    if( *dwCharCount < dwRequiredSize && NULL != pszValue ) {

        lResult = ERROR_SUCCESS;
        *dwCharCount = dwRequiredSize;

        goto FINISHED;
    }

    *dwCharCount = dwRequiredSize;

    ::memcpy( pszValue, static_cast<LPCTSTR>( szTemp ), dwRequiredSize * sizeof( TCHAR ) );

FINISHED:

    return lResult;
}

LONG CAESEncRegKey::ReadNonEncString(CString &szValue) const
{
    LONG    lResult = ERROR_SUCCESS;
    HKEY    hKey    = NULL;
    DWORD    dwSize    = 0;
    BYTE*    pcbData = NULL;

    //
    // Open the key - do not create
    lResult = RegOpenKeyEx( _hKey, _szSubKey, 0, KEY_READ, &hKey );

    //
    // Sanity Check
    if( ERROR_SUCCESS != lResult ) { goto FINISHED; }

    //
    // Query for needed buffer size
    lResult = RegQueryValueEx( hKey, _szValueName, 0, NULL, NULL, &dwSize );

    //
    // Sanity Check
    if( ERROR_SUCCESS != lResult ) { goto FINISHED; }

    //
    // Add '+ sizeof(TCHAR)' in case the string is not
    //   stored in the registry with a trailing '\0'
    pcbData = new BYTE[ dwSize + sizeof(TCHAR) ];

    //
    // Sanity Check
    if( NULL == pcbData ) {        
        lResult = ERROR_NOT_ENOUGH_MEMORY;
        goto FINISHED;
    }

    //
    // Add the trailing '\0', taking into account UNICODEness
    reinterpret_cast<TCHAR*>(pcbData)[ dwSize/sizeof(TCHAR) - 1 ] = _T('\0'); 

    //
    // Query for the actual value
    lResult = RegQueryValueEx( hKey, _szValueName, 0, NULL, pcbData, &dwSize );

    //
    // Sanity Check
    if( ERROR_SUCCESS != lResult ) { goto FINISHED; }

    //
    // Paydirt...
    szValue = reinterpret_cast<TCHAR*>(pcbData);

FINISHED:

    //
    // Cleanup...
    if( NULL != hKey ) { RegCloseKey( hKey ); }

    if( NULL != pcbData ) { delete[] pcbData; }

    return lResult;
}

LONG CAESEncRegKey::ReadEncString(CString &szValue) const
{
    LONG lResult = ERROR_SUCCESS;

    // Returned from the Registry
    DWORD    dwSize    = 0;
    BYTE*    pcbData = NULL;

    // Returned from DecryptData(...)
    DWORD    dwDecryptedSize     = 0;
    BYTE*   pcbDecryptedData = NULL;
  
    // Read From the Registry
    lResult = ReadData( &pcbData, &dwSize );

    //
    // Sanity Check
    if( ERROR_SUCCESS != lResult ) { goto FINISHED; }

    //
    // Undo it...
    lResult = DecryptData( pcbData, dwSize, &pcbDecryptedData, &dwDecryptedSize );

    //
    // Sanity Check
    if( ERROR_SUCCESS != lResult ) { goto FINISHED; }

    //
    // Paydirt...
    szValue = reinterpret_cast<const TCHAR*>( pcbDecryptedData );

FINISHED:

    //
    // Cleanup...
    if( NULL != pcbData ) { delete[] pcbData; }

    if( NULL != pcbDecryptedData ) { delete[] pcbDecryptedData; }

    return lResult;
}

////////////////////////////////
//
// EncryptData
//
LONG CAESEncRegKey::EncryptData(const BYTE *pcbPlainText, DWORD dwPlainTextSize, BYTE **pcbEncryptedData, DWORD *pdwEncryptedSize) const
{
    LONG lResult = ERROR_SUCCESS;

    ASSERT( NULL != pcbPlainText );
    ASSERT( NULL != pcbEncryptedData );
    ASSERT( NULL != pdwEncryptedSize );

    if( NULL == pcbEncryptedData || NULL == pdwEncryptedSize ) {

        lResult = ERROR_INVALID_PARAMETER;
    }

    try {

        CryptoPP::AES::Encryption aesEncryption( _EncKey._cbKey, CryptoPP::AES::DEFAULT_KEYLENGTH);
        CryptoPP::CBC_Mode_ExternalCipher::Encryption cbcEncryption( aesEncryption, _EncIV._cbIV );

        std::string cipher;

        CryptoPP::StreamTransformationFilter stfEncryptor(cbcEncryption, new CryptoPP::StringSink( cipher ) );
        stfEncryptor.Put( reinterpret_cast<const BYTE*>( pcbPlainText ), dwPlainTextSize );
        stfEncryptor.MessageEnd();

        if( ERROR_SUCCESS == lResult ) {
        
            *pdwEncryptedSize = cipher.size();
        
            *pcbEncryptedData = new BYTE[ *pdwEncryptedSize ];

        
            ::memcpy( *pcbEncryptedData, reinterpret_cast<const BYTE*>( cipher.data() ), *pdwEncryptedSize );
        }

    } catch( CryptoPP::Exception& e ) {

        ::OutputDebugString( _T("Caught Crypto++ exception: '") );
        ::OutputDebugStringA( e.what() );
        ::OutputDebugString( _T("'\n") );

        lResult = ERROR_INVALID_DATA;
    
    } catch( ... ) {

        ::OutputDebugString( _T("Caught other exception.") );

        lResult = ERROR_INVALID_DATA;
    }

    return lResult;
}

////////////////////////////////
//
// DecryptData
//
LONG CAESEncRegKey::DecryptData(const BYTE *pcbEncryptedData, DWORD dwEncryptedSize, BYTE **pcbDecryptedData, DWORD *pdwDecryptedSize) const
{
    LONG lResult = ERROR_SUCCESS;

    *pcbDecryptedData = NULL;
    *pdwDecryptedSize = 0;

    try {

        std::string decrypted;
        CryptoPP::AES::Decryption aesDecryption( _EncKey._cbKey, CryptoPP::AES::DEFAULT_KEYLENGTH);
        CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption( aesDecryption, _EncIV._cbIV );
        CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new CryptoPP::StringSink( decrypted ) );

        //
        // Push our blob into the decryptor
        stfDecryptor.Put( pcbEncryptedData, dwEncryptedSize );
        stfDecryptor.MessageEnd();

        *pcbDecryptedData = new BYTE[ decrypted.size() ];

        if( NULL != *pcbDecryptedData ) {

            *pdwDecryptedSize = decrypted.size();

            ::memcpy( *pcbDecryptedData, decrypted.data(), decrypted.size() );
        }
    }

    catch( CryptoPP::Exception& e ) {

        lResult = ERROR_INVALID_DATA;

        ::OutputDebugString( _T("Caught Crypto++ exception: '") );
        ::OutputDebugStringA( e.what() );
        ::OutputDebugString( _T("'\n") );
    }

    catch( ... ) {

        lResult = ERROR_INVALID_DATA;

        ::OutputDebugString( _T("Caught other exception") );
    }

    return lResult;
}

LONG CAESEncRegKey::ReadData(BYTE **pcbData, DWORD *pdwSize) const
{
    LONG    lResult = ERROR_SUCCESS;
    HKEY    hKey    = NULL;

    ASSERT( NULL != pcbData && NULL != pdwSize );

    //
    // Sanity Check
    if( NULL == pcbData || NULL == pdwSize ) {        
        lResult = ERROR_INVALID_PARAMETER;
        goto FINISHED;
    }

    //
    // Open the Key
    lResult = RegOpenKeyEx( _hKey, _szSubKey, 0, KEY_READ, &hKey );

    //
    // Sanity Check
    if( ERROR_SUCCESS != lResult ) { goto FINISHED; }

    //
    // Query for needed buffer size
    lResult = RegQueryValueEx( hKey, _szValueName, 0, NULL, NULL, pdwSize );

    if( ERROR_SUCCESS != lResult ) { goto FINISHED; }

    //
    // Allocate a buffer
    *pcbData = new BYTE[ *pdwSize + sizeof(TCHAR) ];

    //
    // Sanity Check
    if( NULL == *pcbData ) {
        
        lResult = ERROR_NOT_ENOUGH_MEMORY;
        goto FINISHED;
    }

    //
    // Query for the actual value
    lResult = RegQueryValueEx( hKey, _szValueName, 0, NULL, *pcbData, pdwSize );

FINISHED:

    if( NULL != hKey ) { RegCloseKey( hKey ); }

    return lResult;
}

LONG CAESEncRegKey::ReadEncDWORD(DWORD &dwValue) const
{
    LONG lResult = ERROR_SUCCESS;

    // Returned from the Registry by way of ReadData(...)
    DWORD    dwSize    = 0;
    BYTE*    pcbData = NULL;

    // Returned from DecryptData(...)
    DWORD    dwDecryptedSize     = 0;
    BYTE*   pcbDecryptedData = NULL;
  
    // Read From the Registry
    lResult = ReadData( &pcbData, &dwSize );

    //
    // Sanity Check
    if( ERROR_SUCCESS != lResult ) { goto FINISHED; }

    //
    // Undo it...
    lResult = DecryptData( pcbData, dwSize, &pcbDecryptedData, &dwDecryptedSize );

    //
    // Sanity Check
    if( ERROR_SUCCESS != lResult ) { goto FINISHED; }

    //
    // Paydirt...
    dwValue = *( reinterpret_cast<DWORD*>( pcbDecryptedData ) );

FINISHED:

    //
    // Cleanup...
    if( NULL != pcbData ) { delete[] pcbData; }

    if( NULL != pcbDecryptedData ) { delete[] pcbDecryptedData; }

    return lResult;
}

LONG CAESEncRegKey::ReadNonEncDWORD(DWORD& dwValue) const
{
    LONG    lResult = ERROR_SUCCESS;
    HKEY    hKey    = NULL;
    DWORD   dwSize  = sizeof( DWORD );

    //
    // Open the HKey
    lResult = RegOpenKeyEx( _hKey, _szSubKey, 0, KEY_READ, &hKey );

    //
    // Sanity Check
    if( ERROR_SUCCESS != lResult ) { goto FINISHED; }

    //
    // Query for the actual value
    lResult = RegQueryValueEx( hKey, _szValueName, 0, NULL, 
                               reinterpret_cast<BYTE*>(&dwValue), &dwSize );

FINISHED:

    //
    // Cleanup...
    if( NULL != hKey ) { RegCloseKey( hKey ); }

    return lResult;
}

LONG CAESEncRegKey::ReadBinary( BYTE* pcbData, DWORD* dwSize, BOOL bEncrypted /*=FALSE*/) const
{
    LONG lResult = ERROR_SUCCESS;

    if( TRUE == bEncrypted ) {

        lResult = ReadEncBinary( pcbData, dwSize );

    } else {

        lResult = ReadNonEncBinary( pcbData, dwSize );
    }

    return lResult;
}

LONG CAESEncRegKey::ReadNonEncBinary(BYTE* pcbData, DWORD* dwSize) const
{
    LONG    lResult = ERROR_SUCCESS;
    HKEY    hKey    = NULL;

    //
    // Open the HKey
    lResult = RegOpenKeyEx( _hKey, _szSubKey, 0, KEY_READ, &hKey );

    if( ERROR_SUCCESS != lResult ) { goto FINISHED; }

    //
    // Query for the actual value
    lResult = RegQueryValueEx( hKey, _szValueName, 0, NULL, 
                               reinterpret_cast<BYTE*>(pcbData), dwSize );

FINISHED:

    //
    // Cleanup...
    if( NULL != hKey ) { RegCloseKey( hKey ); }

    return lResult;
}

LONG CAESEncRegKey::ReadEncBinary(BYTE* pcbData, DWORD* dwSize) const
{
    LONG lResult = ERROR_SUCCESS;

    //
    // Returned from ReadData(...)
    DWORD dwRegistrySize  = 0;
    BYTE* pcbRegistryData = NULL;

    //
    // Returned from DecryptData(...)
    DWORD dwDecryptedSize  = 0;
    BYTE* pcbDecryptedData = NULL;
  
    //
    // Read From the Registry
    lResult = ReadData( &pcbRegistryData, &dwRegistrySize );

    //
    // Sanity Check
    if( ERROR_SUCCESS != lResult ) { goto FINISHED; }

    //
    // Just undo it...
    lResult = DecryptData( pcbRegistryData, dwRegistrySize, &pcbDecryptedData, &dwDecryptedSize );

    //
    // Sanity Check
    if( ERROR_SUCCESS != lResult ) { goto FINISHED; }

    //
    // Emulate the RegQueryValueEx(...) Function
    //   See http://msdn.microsoft.com/library/default.asp?
    //       url=/library/en-us/sysinfo/base/regqueryvalueex.asp
    if( *dwSize < dwDecryptedSize && NULL != pcbData ) {

        lResult = ERROR_MORE_DATA;
        *dwSize = dwDecryptedSize;

        goto FINISHED;
    }

    //
    // Emulate the RegQueryValueEx(...) Function
    //   See http://msdn.microsoft.com/library/default.asp?
    //       url=/library/en-us/sysinfo/base/regqueryvalueex.asp
    if( *dwSize < dwDecryptedSize && NULL == pcbData ) {

        lResult = ERROR_SUCCESS;
        *dwSize = dwDecryptedSize;

        goto FINISHED;
    }

    //
    // Inform Caller of size of pcbData
    *dwSize = dwDecryptedSize;

    //
    // Copy the Data out
    ::memcpy( pcbData, pcbDecryptedData, dwDecryptedSize );

    lResult = ERROR_SUCCESS;

FINISHED:

    if( NULL != pcbRegistryData )  { delete[] pcbRegistryData; }

    if( NULL != pcbDecryptedData ) { delete[] pcbDecryptedData; }

    return lResult;
}


LONG CAESEncRegKey::WriteData( const BYTE *pcbData, UINT nSize, DWORD dwType /*=REG_BINARY*/) const
{
    LONG lResult = ERROR_SUCCESS;
    HKEY hKey    = NULL;

    //
    // When writing, create the Key if it does not exist
    lResult = RegCreateKeyEx( _hKey, _szSubKey, 0, NULL,
                              REG_OPTION_NON_VOLATILE,
                              KEY_WRITE, NULL, &hKey, NULL );

    //
    // Sanity Check
    if( ERROR_SUCCESS != lResult ) { goto FINISHED; }

    //
    // Paydirt
    lResult = RegSetValueEx( hKey, _szValueName, 0, dwType, 
                             reinterpret_cast<const BYTE*>( pcbData ), nSize );

FINISHED:

    //
    // Cleanup...
    if( NULL != hKey ) { RegCloseKey( hKey ); }

    return lResult;
}

